using System;
using System.Collections.Generic;
using 詞法分析;

namespace 語法分析
{
    /// <summary>
    /// 語法分析器 - 將詞法單元序列構建為抽象語法樹
    /// </summary>
    public class 語法分析器
    {
        private List<詞法單元> 詞法單元列表;
        private int 當前位置;
        private 詞法單元 當前詞法單元;
        
        /// <summary>
        /// 構造函數
        /// </summary>
        public 語法分析器()
        {
            當前位置 = 0;
        }
        
        /// <summary>
        /// 分析詞法單元列表並構建抽象語法樹
        /// </summary>
        /// <param name="詞法單元列表">詞法單元列表</param>
        /// <returns>程序節點（抽象語法樹根節點）</returns>
        public 程序節點 分析(List<詞法單元> 詞法單元列表)
        {
            this.詞法單元列表 = 詞法單元列表;
            this.當前位置 = 0;
            this.當前詞法單元 = 詞法單元列表.Count > 0 ? 詞法單元列表[0] : null;
            
            return 解析程序();
        }
        
        /// <summary>
        /// 解析程序
        /// </summary>
        /// <returns>程序節點</returns>
        private 程序節點 解析程序()
        {
            var 程序 = new 程序節點();
            
            while (當前詞法單元 != null && 當前詞法單元.類型 != 詞法單元類型.文件結束)
            {
                var 語句 = 解析語句();
                if (語句 != null)
                {
                    程序.語句列表.Add(語句);
                }
            }
            
            return 程序;
        }
        
        /// <summary>
        /// 解析語句
        /// </summary>
        /// <returns>語句節點</returns>
        private 語句節點 解析語句()
        {
            if (當前詞法單元 == null)
                return null;
                
            switch (當前詞法單元.類型)
            {
                case 詞法單元類型.吾有:
                    return 解析變量聲明();
                case 詞法單元類型.有術:
                    return 解析函數定義();
                case 詞法單元類型.若:
                    return 解析條件語句();
                case 詞法單元類型.恆為是:
                    return 解析循環語句();
                case 詞法單元類型.云:
                    return 解析輸出語句();
                case 詞法單元類型.乃得:
                    return 解析返回語句();
                case 詞法單元類型.施:
                    return 解析賦值語句();
                default:
                    // 跳過未知的詞法單元
                    前進();
                    return null;
            }
        }
        
        /// <summary>
        /// 解析變量聲明
        /// 語法：吾有一數，曰「變量名」，其值表達式也。
        /// </summary>
        /// <returns>變量聲明節點</returns>
        private 變量聲明節點 解析變量聲明()
        {
            var 節點 = new 變量聲明節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "吾有"
            期望(詞法單元類型.吾有);
            
            // 解析類型（一數、一言、一列）
            if (當前詞法單元.類型 == 詞法單元類型.一數 || 
                當前詞法單元.類型 == 詞法單元類型.一言 || 
                當前詞法單元.類型 == 詞法單元類型.一列)
            {
                節點.變量類型 = 當前詞法單元.值;
                前進();
            }
            else
            {
                拋出語法錯誤("期望變量類型（一數、一言、一列）");
            }
            
            // 消費 "，曰"
            期望(詞法單元類型.曰);
            
            // 解析變量名（字符串字面量）
            if (當前詞法單元.類型 == 詞法單元類型.字符串)
            {
                節點.變量名稱 = 當前詞法單元.值;
                前進();
            }
            else
            {
                拋出語法錯誤("期望變量名稱");
            }
            
            // 可選的初始值
            if (當前詞法單元?.類型 == 詞法單元類型.其值)
            {
                前進(); // 消費 "其值"
                節點.初始值 = 解析表達式();
            }
            
            // 消費 "也"
            期望(詞法單元類型.也);
            
            return 節點;
        }
        
        /// <summary>
        /// 解析函數定義
        /// 語法：有術曰「函數名」，欲行是術，必先得二數，曰「參數1」、曰「參數2」。...是謂「函數名」之術也。
        /// </summary>
        /// <returns>函數定義節點</returns>
        private 函數定義節點 解析函數定義()
        {
            var 節點 = new 函數定義節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "有術"
            期望(詞法單元類型.有術);
            期望(詞法單元類型.曰);
            
            // 解析函數名
            if (當前詞法單元.類型 == 詞法單元類型.字符串)
            {
                節點.函數名稱 = 當前詞法單元.值;
                前進();
            }
            else
            {
                拋出語法錯誤("期望函數名稱");
            }
            
            // 可選的參數列表
            if (當前詞法單元?.類型 == 詞法單元類型.欲行是術)
            {
                前進(); // 消費 "欲行是術"
                
                if (當前詞法單元?.類型 == 詞法單元類型.必先得)
                {
                    前進(); // 消費 "必先得"
                    解析參數列表(節點);
                }
            }
            
            // 解析函數體
            while (當前詞法單元 != null && 當前詞法單元.類型 != 詞法單元類型.是謂)
            {
                var 語句 = 解析語句();
                if (語句 != null)
                {
                    節點.函數體.Add(語句);
                }
            }
            
            // 消費函數結束標記
            期望(詞法單元類型.是謂);
            if (當前詞法單元?.類型 == 詞法單元類型.字符串)
            {
                前進(); // 跳過函數名
            }
            期望(詞法單元類型.之術也);
            
            return 節點;
        }
        
        /// <summary>
        /// 解析參數列表
        /// </summary>
        /// <param name="函數節點">函數定義節點</param>
        private void 解析參數列表(函數定義節點 函數節點)
        {
            // 解析參數類型和數量
            if (當前詞法單元.類型 == 詞法單元類型.一數 || 
                當前詞法單元.類型 == 詞法單元類型.一言 || 
                當前詞法單元.類型 == 詞法單元類型.一列)
            {
                string 參數類型 = 當前詞法單元.值;
                前進();
                
                // 解析參數名列表
                while (當前詞法單元?.類型 == 詞法單元類型.曰)
                {
                    前進(); // 消費 "曰"
                    
                    if (當前詞法單元.類型 == 詞法單元類型.字符串)
                    {
                        var 參數 = new 參數節點(當前詞法單元.行號, 當前詞法單元.列號)
                        {
                            參數類型 = 參數類型,
                            參數名稱 = 當前詞法單元.值
                        };
                        函數節點.參數列表.Add(參數);
                        前進();
                    }
                    
                    // 跳過頓號
                    if (當前詞法單元?.類型 == 詞法單元類型.頓號)
                    {
                        前進();
                    }
                }
            }
        }
        
        /// <summary>
        /// 解析條件語句
        /// 語法：若表達式者，...若非，...云云。
        /// </summary>
        /// <returns>條件語句節點</returns>
        private 條件語句節點 解析條件語句()
        {
            var 節點 = new 條件語句節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "若"
            期望(詞法單元類型.若);
            
            // 解析條件表達式
            節點.條件表達式 = 解析表達式();
            
            // 消費 "者"
            期望(詞法單元類型.者);
            
            // 解析真分支
            while (當前詞法單元 != null && 
                   當前詞法單元.類型 != 詞法單元類型.若非 && 
                   當前詞法單元.類型 != 詞法單元類型.云云)
            {
                var 語句 = 解析語句();
                if (語句 != null)
                {
                    節點.真分支.Add(語句);
                }
            }
            
            // 可選的假分支
            if (當前詞法單元?.類型 == 詞法單元類型.若非)
            {
                前進(); // 消費 "若非"
                
                while (當前詞法單元 != null && 當前詞法單元.類型 != 詞法單元類型.云云)
                {
                    var 語句 = 解析語句();
                    if (語句 != null)
                    {
                        節點.假分支.Add(語句);
                    }
                }
            }
            
            // 消費 "云云"
            期望(詞法單元類型.云云);
            
            return 節點;
        }
        
        /// <summary>
        /// 解析循環語句
        /// 語法：恆為是。...云云。
        /// </summary>
        /// <returns>循環語句節點</returns>
        private 循環語句節點 解析循環語句()
        {
            var 節點 = new 循環語句節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "恆為是"
            期望(詞法單元類型.恆為是);
            
            // 解析循環體
            while (當前詞法單元 != null && 當前詞法單元.類型 != 詞法單元類型.云云)
            {
                var 語句 = 解析語句();
                if (語句 != null)
                {
                    節點.循環體.Add(語句);
                }
            }
            
            // 消費 "云云"
            期望(詞法單元類型.云云);
            
            return 節點;
        }
        
        /// <summary>
        /// 解析輸出語句
        /// 語法：云表達式。
        /// </summary>
        /// <returns>輸出語句節點</returns>
        private 輸出語句節點 解析輸出語句()
        {
            var 節點 = new 輸出語句節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "云"
            期望(詞法單元類型.云);
            
            // 解析輸出表達式
            節點.輸出表達式 = 解析表達式();
            
            return 節點;
        }
        
        /// <summary>
        /// 解析返回語句
        /// 語法：乃得表達式。
        /// </summary>
        /// <returns>返回語句節點</returns>
        private 返回語句節點 解析返回語句()
        {
            var 節點 = new 返回語句節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "乃得"
            期望(詞法單元類型.乃得);
            
            // 解析返回值表達式
            節點.返回值 = 解析表達式();
            
            return 節點;
        }
        
        /// <summary>
        /// 解析賦值語句
        /// 語法：施表達式於變量，名之曰新值。
        /// </summary>
        /// <returns>賦值語句節點</returns>
        private 賦值語句節點 解析賦值語句()
        {
            var 節點 = new 賦值語句節點(當前詞法單元.行號, 當前詞法單元.列號);
            
            // 消費 "施"
            期望(詞法單元類型.施);
            
            // 解析賦值表達式
            節點.賦值表達式 = 解析表達式();
            
            // 消費 "於"
            期望(詞法單元類型.於);
            
            // 解析變量名
            if (當前詞法單元.類型 == 詞法單元類型.字符串 || 當前詞法單元.類型 == 詞法單元類型.標識符)
            {
                節點.變量名稱 = 當前詞法單元.值;
                前進();
            }
            else
            {
                拋出語法錯誤("期望變量名稱");
            }
            
            return 節點;
        }
        
        /// <summary>
        /// 解析表達式
        /// </summary>
        /// <returns>表達式節點</returns>
        private 表達式節點 解析表達式()
        {
            return 解析比較表達式();
        }
        
        /// <summary>
        /// 解析比較表達式
        /// </summary>
        /// <returns>表達式節點</returns>
        private 表達式節點 解析比較表達式()
        {
            var 左表達式 = 解析算術表達式();
            
            while (當前詞法單元?.類型 == 詞法單元類型.大於 || 
                   當前詞法單元?.類型 == 詞法單元類型.小於 || 
                   當前詞法單元?.類型 == 詞法單元類型.等於)
            {
                var 運算符 = 當前詞法單元.值;
                var 行號 = 當前詞法單元.行號;
                var 列號 = 當前詞法單元.列號;
                前進();
                
                var 右表達式 = 解析算術表達式();
                
                左表達式 = new 二元運算表達式節點(行號, 列號)
                {
                    左操作數 = 左表達式,
                    運算符 = 運算符,
                    右操作數 = 右表達式
                };
            }
            
            return 左表達式;
        }
        
        /// <summary>
        /// 解析算術表達式
        /// </summary>
        /// <returns>表達式節點</returns>
        private 表達式節點 解析算術表達式()
        {
            var 左表達式 = 解析基本表達式();
            
            while (當前詞法單元?.類型 == 詞法單元類型.加 || 
                   當前詞法單元?.類型 == 詞法單元類型.減 ||
                   當前詞法單元?.類型 == 詞法單元類型.乘 ||
                   當前詞法單元?.類型 == 詞法單元類型.除)
            {
                var 運算符 = 當前詞法單元.值;
                var 行號 = 當前詞法單元.行號;
                var 列號 = 當前詞法單元.列號;
                前進();
                
                var 右表達式 = 解析基本表達式();
                
                左表達式 = new 二元運算表達式節點(行號, 列號)
                {
                    左操作數 = 左表達式,
                    運算符 = 運算符,
                    右操作數 = 右表達式
                };
            }
            
            return 左表達式;
        }
        
        /// <summary>
        /// 解析基本表達式
        /// </summary>
        /// <returns>表達式節點</returns>
        private 表達式節點 解析基本表達式()
        {
            if (當前詞法單元 == null)
                return null;
                
            switch (當前詞法單元.類型)
            {
                case 詞法單元類型.數字:
                    return 解析數字字面量();
                case 詞法單元類型.字符串:
                    return 解析字符串字面量();
                case 詞法單元類型.標識符:
                    return 解析標識符或函數調用();
                default:
                    拋出語法錯誤($"意外的詞法單元: {當前詞法單元.類型}");
                    return null;
            }
        }
        
        /// <summary>
        /// 解析數字字面量
        /// </summary>
        /// <returns>字面量表達式節點</returns>
        private 字面量表達式節點 解析數字字面量()
        {
            var 節點 = new 字面量表達式節點(當前詞法單元.行號, 當前詞法單元.列號)
            {
                類型 = 詞法單元類型.數字
            };
            
            // 嘗試解析為數字
            if (關鍵字表.是文言文數字(當前詞法單元.值))
            {
                節點.值 = 關鍵字表.轉換為數字(當前詞法單元.值);
            }
            else if (double.TryParse(當前詞法單元.值, out double 數值))
            {
                節點.值 = 數值;
            }
            else
            {
                拋出語法錯誤($"無效的數字格式: {當前詞法單元.值}");
            }
            
            前進();
            return 節點;
        }
        
        /// <summary>
        /// 解析字符串字面量
        /// </summary>
        /// <returns>字面量表達式節點</returns>
        private 字面量表達式節點 解析字符串字面量()
        {
            var 節點 = new 字面量表達式節點(當前詞法單元.行號, 當前詞法單元.列號)
            {
                類型 = 詞法單元類型.字符串,
                值 = 當前詞法單元.值
            };
            
            前進();
            return 節點;
        }
        
        /// <summary>
        /// 解析標識符或函數調用
        /// </summary>
        /// <returns>表達式節點</returns>
        private 表達式節點 解析標識符或函數調用()
        {
            string 名稱 = 當前詞法單元.值;
            int 行號 = 當前詞法單元.行號;
            int 列號 = 當前詞法單元.列號;
            前進();
            
            // 簡化處理：暫時都當作標識符
            return new 標識符表達式節點(行號, 列號)
            {
                名稱 = 名稱
            };
        }
        
        /// <summary>
        /// 期望特定類型的詞法單元
        /// </summary>
        /// <param name="期望類型">期望的詞法單元類型</param>
        private void 期望(詞法單元類型 期望類型)
        {
            if (當前詞法單元?.類型 != 期望類型)
            {
                拋出語法錯誤($"期望 {期望類型}，但得到 {當前詞法單元?.類型}");
            }
            前進();
        }
        
        /// <summary>
        /// 前進到下一個詞法單元
        /// </summary>
        private void 前進()
        {
            當前位置++;
            if (當前位置 < 詞法單元列表.Count)
            {
                當前詞法單元 = 詞法單元列表[當前位置];
            }
            else
            {
                當前詞法單元 = null;
            }
        }
        
        /// <summary>
        /// 拋出語法錯誤
        /// </summary>
        /// <param name="消息">錯誤消息</param>
        private void 拋出語法錯誤(string 消息)
        {
            string 位置信息 = 當前詞法單元 != null ? 
                $"在第 {當前詞法單元.行號} 行第 {當前詞法單元.列號} 列" : "在文件末尾";
            throw new Exception($"語法錯誤 {位置信息}: {消息}");
        }
    }
} 